/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkSipHeader.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkLog.h"

Uint32 CMkSipAcceptEncoding::Parse(const MkString& strEncoding)
{
    return NoneError;
}

Uint32 CMkSipAcceptEncoding::ToString(MkString& strEncoding) const
{
    return NoneError;
}

Uint32 CMkSipAcceptEncoding::GetParamValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it == m_MapParam.end()) {
        return InvalidParams;
    }
    strValue = it->second;
    return NoneError;
}

Uint32 CMkSipAcceptEncoding::UpdateParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
    return NoneError;
}

Uint32 CMkSipContentType::Parse(const MkString& strContentType)
{
    MkVectorString VecValue;
    CMkUtil::StringSplit(strContentType, ";", VecValue);
    size_t nPos = VecValue[0].find('/');
    if (MkString::npos != nPos) {
        m_Type = VecValue[0].substr(0, nPos);
        m_SubType = VecValue[0].substr(nPos);
    }

    for (size_t i = 1; i < VecValue.size(); i++) {
        MkVectorString VecParam;
        CMkUtil::StringSplit(VecValue[i], "=", VecParam);
        if (VecParam.size() > 1) {
            m_MapParam[VecParam[0]] = VecParam[1];
        } else {
            m_MapParam[VecParam[1]] = "";
        }
    }
    return NoneError;
}

Uint32 CMkSipContentType::ToString(MkString& strContentType) const
{
    strContentType = m_Type + "/" + m_SubType;
    MkMapString::const_iterator it = m_MapParam.begin();
    for (; it != m_MapParam.end(); it++) {
        strContentType += ";" + it->first;
        if (!it->second.empty()) {
            strContentType += "=" + it->second;
        }
    }
    return NoneError;
}

Uint32 CMkSipContentType::GetParamValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it == m_MapParam.end()) {
        return InvalidParams;
    }
    strValue = it->second;
    return NoneError;
}

Uint32 CMkSipContentType::UpdateParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
    return NoneError;
}


Uint32 CMkSipAuthorization::Parse(const MkString& strAuthorization)
{
    size_t nSpacePos = strAuthorization.find(' ');
    MkCheckStringPos(nSpacePos, "string:%s not find any space\n", strAuthorization.c_str());
    m_AuthType = strAuthorization.substr(0, nSpacePos);
    nSpacePos++;
    MkVectorString VecString;
    CMkUtil::StringSplit(strAuthorization.substr(nSpacePos), ",", VecString);
    for (size_t i = 0; i < VecString.size(); i++) {
        MkVectorString VecParam;
        CMkUtil::StringSplit(VecString[i], "=", VecParam);
        if (VecParam.size() > 1) {
            CMkUtil::TrimString(VecParam[0]);
            CMkUtil::TrimString(VecParam[1]);
            m_MapParam[VecParam[0]] = VecParam[1];
        }
    }
    return NoneError;
}

Uint32 CMkSipAuthorization::ToString(MkString& strAuthorization) const
{
    strAuthorization = m_AuthType + " ";
    MkMapString::const_iterator it = m_MapParam.begin();
    for (; it != m_MapParam.end(); it++) {
        if (it->second.empty() || it->first.empty()) {
            continue;
        }
        if (it != m_MapParam.begin()) {
            strAuthorization += ", ";
        }
        strAuthorization += it->first + "=" + it->second;
    }
    return NoneError;
}

void CMkSipAuthorization::AddParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
}

Uint32 CMkSipAuthorization::GetParam(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it != m_MapParam.end()) {
        strValue = it->second;
        return NoneError;
    }
    return InvalidParams;
}

CMkSipUri::CMkSipUri()
    : m_Scheme("sip")
    , m_Port(0)
{

}

Uint32 CMkSipUri::Parse(const MkString& strUri)
{
    size_t nUserPoss = strUri.find(':');
    MkCheckStringPos(nUserPoss, "not find host first\n");

    m_Scheme = strUri.substr(0, nUserPoss);
    nUserPoss++;//add : offset

    size_t nUserPassEndPos = strUri.find('@', nUserPoss);
    MkCheckStringPos(nUserPassEndPos, "find user pass end failed\n");

    size_t nPassPos = strUri.find(':', nUserPoss);
    if (MkString::npos != nPassPos && nPassPos < nUserPassEndPos) {
        m_UserName = strUri.substr(nUserPoss, nPassPos - nUserPoss);
        nPassPos++;
        m_Password = strUri.substr(nPassPos, nUserPassEndPos - nPassPos);
    } else {
        m_UserName = strUri.substr(nUserPoss, nUserPassEndPos - nUserPoss);
    }
    nUserPassEndPos++;

    size_t nHeaderPos = strUri.find('?', nUserPassEndPos);
    size_t nParamPos = strUri.find(";", nUserPassEndPos);
    MkString strHostPort;
    MkString strHeaders;
    MkString strParams;
    //has headers
    if (MkString::npos != nHeaderPos) {
        strHostPort = strUri.substr(nUserPassEndPos, nHeaderPos - nUserPassEndPos);
        nHeaderPos++;
        //has param
        if (MkString::npos != nParamPos) {
            strHeaders = strUri.substr(nHeaderPos, nParamPos - nHeaderPos);
            nParamPos++;
            strParams = strUri.substr(nParamPos);
        } else {
            strHeaders = strUri.substr(nHeaderPos);
        }
    } else {
        if (MkString::npos != nParamPos) {
            strHostPort = strUri.substr(nUserPassEndPos, nParamPos);
            nParamPos++;
            strParams = strUri.substr(nParamPos);
        } else {
            strHostPort = strUri.substr(nUserPassEndPos);
        }
    }
    if (strHostPort.empty()) {
        MkErrorLog("host port is empty\n");
        return InvalidParams;
    }

    //parse host port
    size_t nPos = strHostPort.find('['); //ipv6
    size_t nPortPos = MkString::npos;
    if (MkString::npos != nPos) {
        nPos++;
        size_t nEndPos = strHostPort.find(']', nPos);
        MkCheckStringPos(nEndPos, "host invalid\n");
        m_Host = strHostPort.substr(nPos, nEndPos - nPos);
        nEndPos++;
        nPortPos = strHostPort.find(':', nEndPos);
        if (MkString::npos != nPortPos) {
            nPortPos++;
            m_Port = std::stoi(strHostPort.substr(nPortPos));
        }
    } else {
        nPortPos = strHostPort.find(':');
        if (MkString::npos == nPortPos) {
            m_Host = strHostPort;
        } else {
            m_Host = strHostPort.substr(0, nPortPos);
            nPortPos++;
            m_Port = std::stoi(strHostPort.substr(nPortPos));
        }
    }

    if (!strHeaders.empty()) {
        //parse headers
        MkVectorString VecHeaders;
        CMkUtil::StringSplit(strHeaders, "&", VecHeaders);
        for (size_t i = 1; i < VecHeaders.size(); i++) {
            MkVectorString VecParam;
            CMkUtil::StringSplit(VecHeaders[i], "=", VecParam);
            if (VecParam.size() > 1) {
                m_MapHeader[VecParam[0]] = VecParam[1];
            } else {
                m_MapHeader[VecParam[1]] = "";
            }
        }
    }

    if (!strParams.empty()) {
        //parse params
        MkVectorString VecValues;
        CMkUtil::StringSplit(strParams, ";", VecValues);
        for (size_t i = 0; i < VecValues.size(); i++) {
            MkVectorString VecParam;
            CMkUtil::StringSplit(VecValues[i], "=", VecParam);
            if (VecParam.size() > 1) {
                m_MapParam[VecParam[0]] = VecParam[1];
            } else {
                m_MapParam[VecParam[1]] = "";
            }
        }
    }
    return NoneError;
}

Uint32 CMkSipUri::ToString(MkString& strUri) const
{
    strUri = m_Scheme + ":" + m_UserName;
    if (!m_Password.empty()) {
        strUri += ":" + m_Password;
    }

    //ipv6
    if (MkString::npos != m_Host.find(':')) {
        strUri += "@[" + m_Host + "]";
    } else {
        strUri += "@" + m_Host;
    }

    if (0 != m_Port) {
        strUri += ":" + std::to_string(m_Port);
    }

    if (!m_MapHeader.empty()) {
        strUri += "?";
        MkMapString::const_iterator itHeader = m_MapHeader.begin();
        for (; itHeader != m_MapHeader.end(); itHeader++) {
            if (itHeader != m_MapHeader.begin()) {
                strUri += "&";
            }
            strUri += itHeader->first;
            if (!itHeader->second.empty()) {
                strUri += "=" + itHeader->second;
            }
        }
    }

    MkMapString::const_iterator it = m_MapParam.begin();
    for (; it != m_MapParam.end(); it++) {
        strUri += ";" + it->first;
        if (!it->second.empty()) {
            strUri += "=" + it->second;
        }
    }
    return NoneError;
}

Uint32 CMkSipUri::GetParamValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it != m_MapParam.end()) {
        strValue = it->second;
        return NoneError;
    }
    return InvalidParams;
}

Uint32 CMkSipUri::GetHeaderValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapHeader.find(strKey);
    if (it != m_MapHeader.end()) {
        strValue = it->second;
        return NoneError;
    }
    return InvalidParams;
}

void CMkSipUri::UpdateParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
}

void CMkSipUri::UpdateHeader(const MkString& strKey, const MkString& strValue)
{
    m_MapHeader[strKey] = strValue;
}

Uint32 CMkSipTo::Parse(const MkString& strTo)
{
    size_t nUriBegin = strTo.find("<");
    size_t nUriEnd = strTo.find(">");
    if (MkString::npos == nUriEnd
        || MkString::npos == nUriBegin
        || nUriBegin >= nUriEnd) {
        MkErrorLog("invalid to:%s\n", strTo.c_str());
        return InvalidParams;
    }

    MkString strUri = strTo.substr(nUriBegin + 1, nUriEnd - nUriBegin - 1);
    Uint32  ErrorCode = m_Uri.Parse(strUri);
    MkCheckErrorLog(ErrorCode, "parse uri failed\n");

    MkString strParam = strTo.substr(nUriEnd + 1);
    MkVectorString VecValue;
    ErrorCode = CMkUtil::StringSplit(strParam, ";", VecValue);
    for (size_t i = 0; i < VecValue.size(); i++) {
        if (VecValue[i].empty()) {
            continue;
        }
        MkVectorString VecParam;
        ErrorCode = CMkUtil::StringSplit(VecValue[i], "=", VecParam);
        if (VecParam.size() > 1) {
            m_MapParam[VecParam[0]] = VecParam[1];
        } else {
            m_MapParam[VecParam[0]] = "";
        }
    }
    return NoneError;
}

Uint32 CMkSipTo::ToString(MkString& strTo) const
{
    MkString strUri;
    Uint32 ErrorCode = m_Uri.ToString(strUri);
    MkCheckErrorLog(ErrorCode, "packet uri failed\n");
    if (!m_DesplayName.empty()) {
        strTo += "\"" + m_DesplayName + "\"";
    }
    strTo += "<" + strUri + ">";
    MkMapString::const_iterator it = m_MapParam.begin();
    for (; it != m_MapParam.end(); it++) {
        strTo += ";" + it->first;
        if (!it->second.empty()) {
            strTo += "=" + it->second;
        }
    }
    return NoneError;
}

void CMkSipTo::UpdateParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
}
Uint32 CMkSipTo::GetParamValue(const MkString& strKey, MkString& strValue) const
{
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it != m_MapParam.end()) {
        strValue = it->second;
        return NoneError;
    }
    return InvalidParams;
}

CMkSipVia::CMkSipVia()
    : m_Port(0)
    , m_Version("2.0")
{

}

Uint32 CMkSipVia::Parse(const MkString& strVia)
{
    MkVectorString VecValue;
    Uint32 ErrorCode = CMkUtil::StringSplit(strVia, " ", VecValue);
    MkCheckErrorLog(ErrorCode, "split via failed\n");
    if (VecValue.size() < 2) {
        MkErrorLog("via:%s is invalid\n", strVia.c_str());
        return InvalidParams;
    }
    ErrorCode = ParseVersionProtocol(VecValue[0]);
    MkCheckErrorLog(ErrorCode, "parse version protocol failed:%s\n", VecValue[0].c_str());

    MkVectorString VecParam;
    ErrorCode = CMkUtil::StringSplit(VecValue[1], ";", VecParam);
    MkCheckErrorLog(ErrorCode, "split string:%s failed\n", VecValue[1].c_str());
    if (VecParam.empty()) {
        return InvalidParams;
    }
    ParseHostPort(VecParam[0]);

    for (size_t i = 1; i < VecParam.size(); i++) {
        MkVectorString VecStr;
        ErrorCode = CMkUtil::StringSplit(VecParam[i], "=", VecStr);

        if (VecStr.size() > 1) {
            if ("branch" == VecStr[0]) {
                m_Branch = VecStr[1];
            } else {
                m_MapParam[VecStr[0]] = VecStr[1];
            }
        } else {
            m_MapParam[VecStr[0]] = "";
        }
    }
    if (VecValue.size() > 2) {
        ParseComment(VecValue[2]);
    }
    return NoneError;
}

Uint32 CMkSipVia::ToString(MkString& strVia) const
{
    strVia = "SIP/" + m_Version + "/" + m_Protocol + " ";
    if (MkString::npos != m_Host.find(':')) {
        strVia += "[" + m_Host + "]";
        if (0 != m_Port) {
            strVia += ":" + std::to_string(m_Port);
        }
    } else {
        strVia += m_Host;
        if (0 != m_Port) {
            strVia += ":" + std::to_string(m_Port);
        }
    }

    MkMapString::const_iterator it = m_MapParam.begin();
    for (; it != m_MapParam.end(); it++) {
        strVia += ";" + it->first;
        if (!it->second.empty()) {
            strVia += "=" + it->second;
        }
    }

    //add branch
    if (!m_Branch.empty()) {
        strVia += ";branch=" + m_Branch;
    }

    if (!m_Comment.empty()) {
        strVia += " (" + m_Comment + ")";
    }
    return NoneError;
}

void CMkSipVia::UpdateParam(const MkString& strKey, const MkString& strValue)
{
    m_MapParam[strKey] = strValue;
}

Uint32 CMkSipVia::GetParamValue(const MkString& strKey, MkString& strValue) const
{
    Uint32 ErrorCode = InvalidParams;
    MkMapString::const_iterator it = m_MapParam.find(strKey);
    if (it != m_MapParam.end()) {
        strValue = it->second;
        ErrorCode = NoneError;
    }
    return ErrorCode;
}

Uint32 CMkSipVia::ParseVersionProtocol(const MkString& Content)
{
    MkVectorString vecString;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, "/", vecString);
    if (vecString.size() < 3 || NoneError != ErrorCode) {
        MkErrorLog("parse version protocol failed content:%s\n", Content.c_str());
        return InvalidParams;
    }
    m_Version = vecString[1];
    m_Protocol = vecString[2];
    return NoneError;
}

Uint32 CMkSipVia::ParseHostPort(const MkString& Content)
{
    size_t nHostEnd = MkString::npos;
    size_t nPos = Content.find('[');
    if (MkString::npos != nPos) {
        nHostEnd = Content.find(']', nPos);
        MkCheckStringPos(nHostEnd, "invalid host string:%s\n", Content.c_str());
        m_Host = Content.substr(nPos, nHostEnd - nPos);
        nHostEnd = Content.find(':', nHostEnd);
        if (MkString::npos != nHostEnd) {
            m_Port = std::stoi(Content.substr(nHostEnd));
        }
    } else {
        nHostEnd = Content.find(':');
        if (MkString::npos != nHostEnd) {
            m_Host = Content.substr(0, nHostEnd);
            nHostEnd++;
            m_Port = std::stoi(Content.substr(nHostEnd));
        } else {
            m_Host = m_Comment;
        }
    }
    return NoneError;
}

Uint32 CMkSipVia::ParseComment(const MkString& Content)
{
    size_t nCommentPos = Content.find('(');
    size_t nCommentEndPos = Content.find(')');
    MkCheckStringPos(nCommentPos, "not find comment\n");
    nCommentPos++;
    MkCheckStringPos(nCommentEndPos, "not find comment end\n");
    m_Comment = Content.substr(nCommentPos, nCommentEndPos - nCommentPos);
    return NoneError;
}
